package com.example.livereplay.common.service.imp;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.livereplay.common.model.enity.Place;
import com.example.livereplay.common.model.enity.SysAttachment;
import com.example.livereplay.common.model.enity.Tournament;
import com.example.livereplay.common.mapper.PlaceMapper;
import com.example.livereplay.common.mapper.SysAttachmentMapper;
import com.example.livereplay.common.mapper.TournamentMapper;
import com.example.livereplay.common.model.request.GetAttachmentRequest;
import com.example.livereplay.common.model.request.InsertAttachmentRequest;
import com.example.livereplay.common.model.request.InsertTournamentRequest;
import com.example.livereplay.common.service.FileUploadService;
import com.example.livereplay.common.service.PlaceService;
import com.example.livereplay.common.service.SysAttachmentService;
import com.example.livereplay.common.service.TournamentService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.data.redis.core.RedisTemplate;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class SysAttachmentServiceImpl extends ServiceImpl<SysAttachmentMapper, SysAttachment> implements SysAttachmentService {



    @Resource
    private SysAttachmentMapper sysAttachmentMapper;
    @Lazy
    @Resource
    public FileUploadService fileUploadService;

    @Resource
    private TournamentService tournamentService;

    @Resource
    private TournamentMapper tournamentMapper;

    @Resource
    private PlaceService placeService;

    @Resource
    private PlaceMapper placeMapper;


    // 本地敏感词汇库，可根据实际情况不断扩充
    private static final Set<String> SENSITIVE_WORDS_SET = new HashSet<>();
    private static final String ATTACHMENT_LIST_KEY_PREFIX = "attachment:list:";
    private static final String ATTACHMENT_BY_VIDEO_KEY_PREFIX = "attachment:by_video:";
    private static final String ATTACHMENT_BY_NAME_KEY_PREFIX = "attachment:by_name:";
    static {
        SENSITIVE_WORDS_SET.add("敏感词1");
        SENSITIVE_WORDS_SET.add("敏感词2");
    }

    @Resource
    private RedisTemplate<String, List<SysAttachment>> redisTemplate;

    @Override
    public List<SysAttachment> getAttachmentList(GetAttachmentRequest getAttachmentRequest) {
        if (StrUtil.isBlank(getAttachmentRequest.getType()) || StrUtil.isBlank(getAttachmentRequest.getId())) {
            return new ArrayList<>();
        }

        String redisKey = ATTACHMENT_LIST_KEY_PREFIX + getAttachmentRequest.getType() + ":" + getAttachmentRequest.getId();

        List<SysAttachment> attachmentList = redisTemplate.opsForValue().get(redisKey);
        if (attachmentList!= null) {
            return attachmentList;
        }
        List<SysAttachment> attachmentIdList = this.list(Wrappers.lambdaQuery(SysAttachment.class)
                .eq(SysAttachment::getType, getAttachmentRequest.getType())
                .eq(SysAttachment::getUserId, getAttachmentRequest.getId())
        );
        if (CollectionUtil.isEmpty(attachmentIdList)) {
            return new ArrayList<>();
        }
        redisTemplate.opsForValue().set(redisKey, attachmentIdList, 1, TimeUnit.HOURS);
        return attachmentIdList;
    }


    @Override
    public List<SysAttachment> getAttachmentByVideo(GetAttachmentRequest getAttachmentRequest) {
        if (StrUtil.isBlank(getAttachmentRequest.getType()) || StrUtil.isBlank(getAttachmentRequest.getId())) {
            return new ArrayList<>();
        }

        String redisKey = ATTACHMENT_BY_VIDEO_KEY_PREFIX + getAttachmentRequest.getId();

        List<SysAttachment> attachmentList = redisTemplate.opsForValue().get(redisKey);
        if (attachmentList!= null) {
            return attachmentList;
        }

        List<SysAttachment> attachmentIdList = this.list(Wrappers.lambdaQuery(SysAttachment.class)
                .eq(SysAttachment::getType, getAttachmentRequest.getType())
                .eq(SysAttachment::getPlaceId, getAttachmentRequest.getId())
        );
        if (CollectionUtil.isEmpty(attachmentIdList)) {
            return new ArrayList<>();
        }

        attachmentIdList = attachmentIdList.stream()
                .sorted(Comparator.comparing(SysAttachment::getTime).reversed())
                .sorted(Comparator.comparing(SysAttachment::getViews).reversed())
                .collect(Collectors.toList());

        redisTemplate.opsForValue().set(redisKey, attachmentIdList, 1, TimeUnit.HOURS);

        return attachmentIdList;
    }

    @Override
    public List<SysAttachment> getAttachmentByName(GetAttachmentRequest getAttachmentRequest) {
        if (StrUtil.isBlank(getAttachmentRequest.getType()) || StrUtil.isBlank(getAttachmentRequest.getId())) {
            return new ArrayList<>();
        }

        String redisKey = ATTACHMENT_BY_NAME_KEY_PREFIX + getAttachmentRequest.getId();

        List<SysAttachment> attachmentList = redisTemplate.opsForValue().get(redisKey);
        if (attachmentList!= null) {
            return attachmentList;
        }

        List<SysAttachment> attachmentIdList = this.list(Wrappers.lambdaQuery(SysAttachment.class)
                .eq(SysAttachment::getType, getAttachmentRequest.getType())
                .like(SysAttachment::getFileName, getAttachmentRequest.getId())
        );
        if (CollectionUtil.isEmpty(attachmentIdList)) {
            return new ArrayList<>();
        }

        attachmentIdList = attachmentIdList.stream()
                .sorted(Comparator.comparing(attachment -> {
                    String fileFileName = attachment.getFileName();
                    if (fileFileName.equals(getAttachmentRequest.getId())) {
                        return 0;
                    } else if (fileFileName.contains(getAttachmentRequest.getId())) {
                        return 1;
                    } else {
                        return 2;
                    }
                }))
                .collect(Collectors.toList());

        attachmentIdList = attachmentIdList.stream()
                .sorted(Comparator.comparing(SysAttachment::getTime).reversed())
                .collect(Collectors.toList());

        attachmentIdList = attachmentIdList.stream()
                .sorted(Comparator.comparing(SysAttachment::getViews).reversed())
                .collect(Collectors.toList());

        // 存入Redis并设置过期时间
        redisTemplate.opsForValue().set(redisKey, attachmentIdList, 1, TimeUnit.HOURS);

        return attachmentIdList;
    }

    @Override
    public Boolean saveAttachment(String type, String userId,String attachmentId)
    {
        SysAttachment sysAttachment=sysAttachmentMapper.selectOne(new LambdaQueryWrapper<SysAttachment>()
                .eq(SysAttachment::getId,attachmentId)
        );
        if(sysAttachment==null)
        {
            return true;
        }
        sysAttachment.setType(type);
        sysAttachment.setUserId(userId);
        return updateById(sysAttachment);
    }

    @Override
    public Boolean saveAttachmentList(InsertAttachmentRequest insertAttachmentRequest)
    {
      List<SysAttachment> updateAttachments=insertAttachmentRequest.getAttachmentId().stream()
              .map(attachmentId->{
                  LambdaQueryWrapper<SysAttachment> wrapper=new LambdaQueryWrapper<SysAttachment>()
                          .eq(SysAttachment::getId,attachmentId);
                  SysAttachment sysAttachment=sysAttachmentMapper.selectOne(wrapper);
                  if(sysAttachment!=null)
                  {
                      sysAttachment.setType(insertAttachmentRequest.getType());
                      sysAttachment.setUserId(insertAttachmentRequest.getUserId());
                  }
                  return sysAttachment;
                      }).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(updateAttachments)) {
            updateBatchById(updateAttachments);
        }
        return true;
    }

    @Override
    public Boolean saveTournamentList(InsertTournamentRequest insertTournamentRequest)
    {
        final Tournament tournament = tournamentMapper.selectOne(new LambdaQueryWrapper<Tournament>()
                .eq(Tournament::getName,insertTournamentRequest.getName())
                .eq(Tournament::getGameEndTime,insertTournamentRequest.getGameEndTime())
                .eq(Tournament::getGameStartTime,insertTournamentRequest.getGameStartTime())
        );
        final Place place =new Place();
        if(tournament==null)
        {
            tournament.setName(insertTournamentRequest.getName());
            tournament.setGameStartTime(insertTournamentRequest.getGameStartTime());
            tournament.setGameEndTime(insertTournamentRequest.getGameEndTime());
            if (tournamentService.save(tournament)) {
                place.setTournamentId(tournament.getId());
                place.setName(insertTournamentRequest.getPlaceName());
                placeService.save(place);
            }
        }
        else{
            final Place newOne=placeMapper.selectOne(new LambdaQueryWrapper<Place>()
                    .eq(Place::getName,insertTournamentRequest.getPlaceName())
                    .eq(Place::getTournamentId,tournament.getId())
            );
            if(newOne!=null) {
                BeanUtil.copyProperties(newOne, place);
            }
            else{
                return false;
            }
        }
        List<SysAttachment> updateAttachments=insertTournamentRequest.getAttachmentIdList().stream()
                .map(attachmentId->{
                    LambdaQueryWrapper<SysAttachment> wrapper=new LambdaQueryWrapper<SysAttachment>()
                            .eq(SysAttachment::getId,attachmentId);
                    SysAttachment sysAttachment=sysAttachmentMapper.selectOne(wrapper);
                    if(sysAttachment!=null)
                    {
                        sysAttachment.setType(insertTournamentRequest.getType());
                        sysAttachment.setPlaceId(place.getId());
                        sysAttachment.setUserId(insertTournamentRequest.getUserId());
                    }
                    return sysAttachment;
                }).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(updateAttachments)) {
            updateBatchById(updateAttachments);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<SysAttachment> uploadVideo(List<MultipartFile> fileList) {
        return fileUploadService.uploadBatchFile("/tournament/video/", fileList,"VIDEOS");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<SysAttachment> uploadNews(List<MultipartFile> fileList) {
        return fileUploadService.uploadBatchFile("/news/", fileList,"NEWS");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<SysAttachment> uploadPhotos(List<MultipartFile> fileList) {
        return fileUploadService.uploadBatchFile("/tournament/photos/", fileList,"PHOTO");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<SysAttachment> getAttachmentListByViews(String type){
        final List<SysAttachment> sysAttachmentList=list(new LambdaQueryWrapper<SysAttachment>()
                .eq(SysAttachment::getType,type)
                .orderByAsc(SysAttachment::getViews)
                .orderByAsc(SysAttachment::getTime)
        );
        if(sysAttachmentList==null)
        {
            return new ArrayList<>();
        }
        return sysAttachmentList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<SysAttachment> getAttachmentListByTime(String type){
        final List<SysAttachment> sysAttachmentList=list(new LambdaQueryWrapper<SysAttachment>()
                .eq(SysAttachment::getType,type)
                .orderByAsc(SysAttachment::getTime)
                .orderByAsc(SysAttachment::getViews)
        );
        if(sysAttachmentList==null)
        {
            return new ArrayList<>();
        }
        return sysAttachmentList;
    }
}
